/*
 * rtl.c
 *
 * The Carlos Runtime Library.
 *
 * Implementation of the nontrivial Carlos standard functions and
 * supporting utilities.  These use the C calling convention, as
 * does the Carlos compiler.  The functions are:
 *
 *   toUTF8z (to preprocess a string before sending to printf)
 *   get_string
 *   get_char
 *   toString
 *   substring
 *   compare
 *   concat
 *   allocate_array
 *   make_slice
 *   object_to_string
 *
 * Note: The following functions from the Carlos standard library are
 * handled internally by the compiler and thus are not included here:
 *
 *   sqrt
 *   pi
 *   sin
 *   cos
 *   atan
 *   ln
 */

#include <stdio.h>
#include <stdlib.h>

/* Make sure C++ compilers don't screw this up */

#ifdef __cplusplus
extern "C" {
#endif

/**
 * A utility function that takes a Carlos string (represented as a
 * pointer to an array of UTF-32 ints, with the length preceding),
 * into a zero-terminated array of bytes containing the corresponding
 * UTF-8 encoding.
 */
char* Carlos(int* a) {
    int i;
    int j;
    int count = 0;
    char* result;
    int length = a[-1];

    /* Determine the number of bytes in the encoding */
    for (i = 0; i < length; i++) {
        int c = a[i];
        count++; if (c < 0x7F) continue;
        count++; if (c < 0x7FF) continue;
        count++; if (c < 0xFFFF) continue;
        count++; if (c < 0x1FFFFF) continue;
        count++; if (c < 0x3FFFFFF) continue;
        count++; if (c < 0x7FFFFFFF) continue;
    }

    /* Allocate space for the encoding plus a terminating zero byte. */
    result = (char*)malloc(count + 1);

    /* Encode */
    for (j = 0, i = 0; i < length; i++) {
        int c = a[i];
        if (c < 0x7F) {
            result[j++] = c;
        } else if (c < 0x7FF) {
            result[j++] = 0xC0 | c>>6;
            result[j++] = 0x80 | c & 0x3F;
        } else if (c < 0xFFFF) {
            result[j++] = 0xE0 | c>>12;
            result[j++] = 0x80 | c>>6 & 0x3F;
            result[j++] = 0x80 | c & 0x3F;
        } else if (c < 0x1FFFFF) {
            result[j++] = 0xF0 | c>>18;
            result[j++] = 0x80 | c>>12 & 0x3F;
            result[j++] = 0x80 | c>>6 & 0x3F;
            result[j++] = 0x80 | c & 0x3F;
        } else if (c <= 0x3FFFFFF) {
            result[j++] = 0xF8 | c>>24;
            result[j++] = 0x80 | c>>18 & 0x3F;
            result[j++] = 0x80 | c>>12 & 0x3F;
            result[j++] = 0x80 | c>>6 & 0x3F;
            result[j++] = 0x80 | c & 0x3F;
        } else if (c <= 0x7FFFFFFF) {
            result[j++] = 0xFC | c>>30;
            result[j++] = 0x80 | c>>24 & 0x3F;
            result[j++] = 0x80 | c>>18 & 0x3F;
            result[j++] = 0x80 | c>>12 & 0x3F;
            result[j++] = 0x80 | c>>6 & 0x3F;
            result[j++] = 0x80 | c & 0x3F;
       }
   }

   /* Add the terminating 0 byte */
   result[j++] = '\0';
   return result;
}

//string Carlos_format(string format, ...)

// string Carlos_print(string format, ...)
//   fwrite(s, 1, *(int*)(s - WORD_SIZE), stdout);

/*
 *
 */
int* Carlos_getString() {
    return 0; /* NOT DONE YET */
}

/*
 *
 */
int Carlos_getChar() {
    return 0; /* NOT DONE YET */
}

/*
 *
 */
int* Carlos_toString() {
    return 0; /* NOT DONE YET */
}

/*
 * string substring(string s, int first, int n)
 *
 * Return a new string which is the n characters beginning at index
 * first within s.  Characters are numbered starting at 0.  If first
 * is beyond the end of s, returns the empty string. If length is
 * too large, then the returned string consists only of the characters
 * up to the end of s.
 */
int* Carlos_substring(char* s, int first, int n) {
    int length = s[-1];
    int* result;
    int* p;
    int i;

    if (first < 0 || first >= length || n <= 0) {
        /* Will want the empty string on invalid first or negative lengths */
        n = 0;
    } else if (first + n >= length) {
        /* Will need to cut off the substring */
        n = length - first;
    }

    /* Now allocate space for the substring and fill it. */
    result = (int*)malloc((1 + n) * sizeof(int));
    *result = n;
    result += 1;
    p = result;
    for (i = 0; i < n; i++) {
      *p++ = s[i];
    }
    return result;
}


/*
 * int compare(string s1, string s2)
 *
 * Compares two Carlos strings, s1 and s2.  Returns a negative value
 * if s1 is lexicographically less than s2, zero if they are equal,
 * and a positive value otherwise.
 */
int Carlos_compare(int* s1, int* s2) {
    int length1 = *(s1 - 1);
    int length2 = *(s2 - 1);

    return 0; /* NOT DONE YET */
}


/*
 * string concat(string s1, string s2)
 *
 * Returns the concatenation of s1 and s2.
 */
int* Carlos_concat(int* s1, int* s2) {
    int length1 = s1[-1];
    int length2 = s2[-1];
    int* result = (int*)malloc((1 + length1 + length2) * sizeof(int));
    int* p;
    int i;

    *result = length1 + length2;
    result += 1;
    p = result;
    for (i = 0; i < length1; i++) {
        *p++ = s1[i];
    }
    for (i = 0; i < length2; i++) {
        *p++ = s2[i];
    }
    return result;
}

#ifdef __cplusplus
}
#endif
